home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 June: Reference Library / Dev.CD Jun 96 RL / Dev.CD Jun 96 RL.toast / Technical Documentation / develop / develop Issue 24 / develop Issue 24 code / Scriptable Database 1.0a15 / Foundation / ProxyToken.cp < prev    next >
Encoding:
Text File  |  1996-02-19  |  27.3 KB  |  895 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        ProxyToken.c
  3.  
  4.     Contains:    A proxy token acts on behalf of some other group
  5.                 of objects (for example, the selection)
  6.  
  7.     Written by:    Greg Anderson
  8.  
  9.     Copyright:    © 1993-1995 by Apple Computer, Inc., all rights reserved.
  10.  
  11.         <10>     6/23/95    ga
  12. */
  13.  
  14. #ifdef MWTRACEBACKTABLES
  15. #pragma traceback on
  16. #endif
  17.  
  18.  
  19. #include "ProxyToken.h"
  20. #include "ScriptableObjectList.h"
  21. #include "AbstractSearchSpec.h"
  22.  
  23. #include "MoreAEM.h"
  24.  
  25. #define pProperties                'prps'                // The "properties" property
  26.  
  27. #include <AppleEvents.h>
  28. #include <AERegistry.h>
  29. #include <ASRegistry.h>
  30. #include <AEPackObject.h>
  31. #include <OSUtils.h>
  32.  
  33. #include "Exceptions.h"
  34.  
  35.  
  36. #include "Debug.h"
  37.  
  38.  
  39. //========================================================================================
  40. // CLASS TProxyToken
  41. //
  42. // This token represents a group of other objects
  43. //========================================================================================
  44.  
  45. #pragma segment ObjectResident
  46. ImplementSmallClassData(TProxyToken, clProxyToken);
  47.  
  48. #pragma segment ProxyToken
  49.  
  50. //----------------------------------------------------------------------------------------
  51. // TProxyToken::TProxyToken: 
  52. //----------------------------------------------------------------------------------------
  53. TProxyToken::TProxyToken()
  54.     {
  55.     } // TProxyToken::TProxyToken 
  56.  
  57. //----------------------------------------------------------------------------------------
  58. // TProxyToken::~TProxyToken: 
  59. //----------------------------------------------------------------------------------------
  60. TProxyToken::~TProxyToken()
  61.     {
  62.     } // TProxyToken::~TProxyToken 
  63.  
  64. //----------------------------------------------------------------------------------------
  65. // TProxyToken::IProxyToken: 
  66. //----------------------------------------------------------------------------------------
  67. void TProxyToken::IProxyToken(TAbstractScriptableObject* objectOfDesignation)
  68.     {
  69.     TAbstractDesignator::IAbstractDesignator(objectOfDesignation);
  70.     } // TProxyToken::IProxyToken 
  71.  
  72. //----------------------------------------------------------------------------------------
  73. // TProxyToken::DerivedFromOSLClass: 
  74. //----------------------------------------------------------------------------------------
  75. Boolean TProxyToken::DerivedFromOSLClass(const TAETransaction& t, DescType objectClass)
  76.     {
  77.     return (objectClass == cProxy) || (Inherited::DerivedFromOSLClass(t, objectClass));
  78.     } // TProxyToken::DerivedFromOSLClass 
  79.  
  80. //----------------------------------------------------------------------------------------
  81. // TProxyToken::DefaultType: 
  82. //
  83. // The default type of a proxy token is typeAEList so that the selection will always
  84. // return a list, even if only one item is selected.  'typeAEList' isn't really a type
  85. // that can be generated (it has to be a list of something), so the best type of this
  86. // object (typeObjectSpecifier, in this case) is used to determine what should go in
  87. // the list.
  88. //----------------------------------------------------------------------------------------
  89. DescType TProxyToken::DefaultType(const TAETransaction& t, DescType propertyName)
  90.     {
  91.     DescType defaultType = 0;
  92.     
  93.     if(propertyName == pContents)
  94.         defaultType = typeAEList;
  95.     else if(this->PropertyAppliesToProxy(propertyName))
  96.         defaultType = Inherited::DefaultType(t, propertyName);
  97.     else
  98.         {
  99. #if 0
  100.         TAbstractObjectIterator* iter = this->DirectObjectIterator(t);
  101.         for(iter->Reset(t); iter->More(t); iter->Next(t))
  102.             {
  103.             TAbstractScriptableObject* token = iter->Current(t);
  104.             DescType defaultOfThisToken = token->DefaultType(t, propertyName);
  105.             token->DisposeDesignator();
  106.             
  107.             //
  108.             // If we don't have a default type yet, just remember this
  109.             // token's default type
  110.             //
  111.             if(defaultType == 0)
  112.                 defaultType = defaultOfThisToken;
  113.             //
  114.             // If all of the tokens are in agreement about their default type,
  115.             // then we'll use that.  Otherwise, use typeWildCard to indicate
  116.             // that there are multiple best types to use.
  117.             //
  118.             else if(defaultType != defaultOfThisToken)
  119.                 defaultType = typeWildCard;
  120.             }
  121. #else
  122.         defaultType = typeWildCard;
  123. #endif
  124.         }
  125.     
  126.     return defaultType;
  127.     } // TProxyToken::DefaultType 
  128.  
  129. //----------------------------------------------------------------------------------------
  130. // TProxyToken::BestType: 
  131. //----------------------------------------------------------------------------------------
  132. DescType TProxyToken::BestType(const TAETransaction& t, DescType propertyName)
  133.     {
  134.     DescType bestType = 0;
  135.     
  136.     if(propertyName == pContents)
  137.         bestType = typeObjectSpecifier;
  138.     else if(this->PropertyAppliesToProxy(propertyName))
  139.         bestType = Inherited::BestType(t, propertyName);
  140.     else
  141.         {
  142. #if 0
  143.         TAbstractObjectIterator* iter = this->DirectObjectIterator(t);
  144.         for(iter->Reset(t); iter->More(t); iter->Next(t))
  145.             {
  146.             TAbstractScriptableObject* token = iter->Current(t);
  147.             DescType bestOfThisToken = token->BestType(t, propertyName);
  148.             token->DisposeDesignator();
  149.                         
  150.             //
  151.             // If we don't have a best type yet, just remember this
  152.             // token's best type
  153.             //
  154.             if(bestType == 0)
  155.                 bestType = bestOfThisToken;
  156.             //
  157.             // If all of the tokens are in agreement about their best type,
  158.             // then we'll use that.  Otherwise, use typeWildCard to indicate
  159.             // that there are multiple best types to use.
  160.             //
  161.             else if(bestType != bestOfThisToken)
  162.                 bestType = typeWildCard;
  163.             }
  164. #else
  165.             bestType = typeBest;
  166. #endif
  167.         }
  168.     
  169.     return bestType;
  170.     } // TProxyToken::BestType 
  171.  
  172. //----------------------------------------------------------------------------------------
  173. // TProxyToken::Exists: 
  174. //
  175. // A proxy token exists if it is posible to access at least one element from it.
  176. //----------------------------------------------------------------------------------------
  177. Boolean TProxyToken::Exists(const TAETransaction& t)
  178.     {
  179.     TAbstractScriptableObject* token = nil;
  180.     Boolean exists = false;
  181.     OSErr err = noErr;
  182.     
  183.     NOREGISTER(token);
  184.     
  185.     Try
  186.         {
  187.         //
  188.         // Accessing the first element is faster than doing a count,
  189.         // even though it may allocate memory
  190.         //
  191.         TAbstractObjectIterator* iter = this->DirectObjectIterator(t);
  192.         token = iter->GetIndexedElement(t, typeWildCard, 1);
  193.         
  194.         //
  195.         // AccessByIndex should fail rather than return nil,
  196.         // but we'll check anyway.
  197.         //
  198.         if(token != nil)
  199.             exists = true;
  200.         }
  201.     Catch(err)
  202.         {
  203.         }
  204.     
  205.     //
  206.     // Delete the token if it was cloned
  207.     //
  208.     if(token != nil)
  209.         token->DisposeDesignator();
  210.     
  211.     return exists;
  212.     } // TProxyToken::Exists 
  213.     
  214. //----------------------------------------------------------------------------------------
  215. // TProxyToken::DirectObjectIterator:
  216. //
  217. // By default, the elements of a proxy token are the same as its children; therefore,
  218. // DirectObjectIterator calls through to ElementIterator.  This is not always true,
  219. // however; see TMarkToken::DirectObjectIterator
  220. //----------------------------------------------------------------------------------------
  221. TAbstractObjectIterator* TProxyToken::DirectObjectIterator(const TAETransaction& t)
  222.     {
  223.     return this->ElementIterator(t);
  224.     } // TProxyToken::DirectObjectIterator 
  225.  
  226. //----------------------------------------------------------------------------------------
  227. // TProxyToken::PropertyAppliesToProxy: 
  228. //----------------------------------------------------------------------------------------
  229. Boolean TProxyToken::PropertyAppliesToProxy(DescType propertyName)
  230.     {
  231.     //
  232.     // Used for properties and ordinals.  All of the ordinals except
  233.     // 'kAEAll' apply to the proxy.
  234.     //
  235.     // Note that the selection token adds pContents and kAEAll, but
  236.     // the mark token does not.  This is because "contents of selection"
  237.     // should return all of the items in the selection (that is, the
  238.     // "contents" property applies to the proxy "selection," not to
  239.     // the items designated by the proxy), but "contents of every disk"
  240.     // should return every item inside of every disk (that is, the
  241.     // "contents" property applies to the tokens designated by the
  242.     // proxy "every disk," not to the proxy itself).
  243.     //
  244.     // WARNING:        Do not add properties or ordinals here lightly!
  245.     //                 This simple function has a profound impact on the
  246.     //                way the foundation classes function.  If you get
  247.     //                one wrong, the code will do _strange_ things
  248.     //                with that property!
  249.     //
  250.     return (    (propertyName == kAEFirst)        ||
  251.                 (propertyName == kAELast)        ||
  252.                 (propertyName == kAEMiddle)        ||
  253.                 (propertyName == kAEAny)        ||
  254.                 (propertyName == pBestType)        ||
  255.                 (propertyName == pDefaultType)
  256.             );
  257.     } // TProxyToken::PropertyAppliesToProxy 
  258.  
  259. //----------------------------------------------------------------------------------------
  260. // TProxyToken::AccessByOrdinal: 
  261. //----------------------------------------------------------------------------------------
  262. TAbstractScriptableObject* TProxyToken::AccessByOrdinal(const TAETransaction& t, DescType desiredClass, DescType ordinal)
  263.     {
  264.     TAbstractScriptableObject* resultToken = nil;
  265.     NOREGISTER(resultToken);
  266.     OSErr err = noErr;
  267.     
  268.     if(this->PropertyAppliesToProxy(ordinal))
  269.         {
  270.         resultToken = Inherited::AccessByOrdinal(t, desiredClass, ordinal);
  271.         }
  272.     else
  273.         {
  274.         TAbstractScriptableObject* token = nil;
  275.         
  276.         NOREGISTER(token);
  277.         
  278.         //
  279.         // If a script command asks for a property of a proxy object,
  280.         // the result returned will be a list of said property retrieved
  281.         // from every item represented by the proxy
  282.         //
  283.         TAbstractObjectIterator* iter = this->DirectObjectIterator(t);
  284.         for(iter->Reset(t); iter->More(t); iter->Next(t))
  285.             {
  286.             Try
  287.                 {
  288.                 token = iter->Current(t);
  289.                 TAbstractScriptableObject* ordinalToken = token->AccessByOrdinal(t, desiredClass, ordinal);
  290.                 ordinalToken->AddThisToMarkToken(resultToken, kSingleItemOrUnion);
  291.                 token->DisposeDesignator();
  292.                 token = nil;
  293.                 }
  294.             Catch(err)
  295.                 {
  296.                 if(token != nil)
  297.                     token->DisposeDesignator();
  298.                 if(resultToken != nil)
  299.                     resultToken->DisposeDesignator();
  300.                 
  301.                 //
  302.                 // ••• should we really fail again?  maybe we
  303.                 // should not return an error if there is at
  304.                 // least one item in the proxy that returns
  305.                 // a valid property.  For now, we only allow
  306.                 // 'no such object' to pass through.
  307.                 //
  308.                 if(err != errAENoSuchObject)
  309.                     Throw(err);
  310.                 }
  311.             }
  312.         }
  313.     
  314.     //
  315.     // Since we allow 'no such object' to pass through above,
  316.     // we must fail here if nothing at all was found.
  317.     //
  318.     if(resultToken == nil)
  319.         FailErr(errAENoSuchObject);
  320.     
  321.     return resultToken;
  322.     } // TProxyToken::AccessByOrdinal 
  323.  
  324. //----------------------------------------------------------------------------------------
  325. // TProxyToken::AccessByProperty: 
  326. //----------------------------------------------------------------------------------------
  327. TAbstractScriptableObject* TProxyToken::AccessByProperty(const TAETransaction& t, DescType propertyName)
  328.     {
  329.     TAbstractScriptableObject* resultToken = nil;
  330.     OSErr err = noErr;
  331.     
  332.     NOREGISTER(resultToken);
  333.     
  334.     //
  335.     // Although most properties of the proxy object apply to its elements,
  336.     // there are a few that apply to the 'proxy' object itself.
  337.     // (You can always say 'default type of every item of <proxy object>' to
  338.     // get these properties as they apply to the elements represented by proxy)
  339.     //
  340.     // Note the special checking for pProperties; we want to generate an
  341.     // ordinary generic token, pProperties of <this proxy> (which we wouldn't
  342.     // get if we tried to look for 'pProperties' in the property list), but we want
  343.     // the GetProperty call to delegate to the tokens of the proxy (which it
  344.     // wouldn't do if pProperties was in 'PropertyAppliesToProxy')
  345.     //
  346.     // ◊Script:  pContents, pEntireContents here?
  347.     //
  348.     if(this->PropertyAppliesToProxy(propertyName)  || (propertyName == pProperties))
  349.         {
  350.         resultToken = Inherited::AccessByProperty(t, propertyName);
  351.         }
  352.     else
  353.         {
  354.         //
  355.         // 'propertyDescription.PropertyIdentifier()' will come back zero if this property is not in
  356.         // the property table of any of the items this proxy designates
  357.         //        
  358.         TPropertyDescription propertyDescription = this->LookupPropertyDesciption(t, propertyName);
  359.         
  360.         if((propertyDescription.PropertyIdentifier() != 0) && (NeverCreateGenericProperty(propertyDescription.AdditionalInfo()) == false))
  361.             {
  362.             resultToken = new TGenericProperty;
  363.             ((TGenericProperty*)resultToken)->IGenericProperty(this, propertyDescription);
  364.             }
  365.         else
  366.             {
  367.             TAbstractScriptableObject* token = nil;
  368.             
  369.             NOREGISTER(token);
  370.             
  371.             //
  372.             // If a script command asks for a property of a proxy object,
  373.             // the result returned will be a list of said property retrieved
  374.             // from every item represented by the proxy
  375.             //
  376.             // ◊Script:        We need to call AccessByProperty in case that the
  377.             //                property being accessed is really a reference
  378.             //                to some object (e.g. the trash); however, 
  379.             //
  380.             TAbstractObjectIterator* iter = this->DirectObjectIterator(t);
  381.             for(iter->Reset(t); iter->More(t); iter->Next(t))
  382.                 {
  383.                 Try
  384.                     {
  385.                     token = iter->Current(t);
  386.                     TAbstractScriptableObject* propertyToken = token->AccessByProperty(t, propertyName);
  387.                     propertyToken->AddThisToMarkToken(resultToken, kPropertyUnion); // was: kSingleItemOrUnion
  388.                     token->DisposeDesignator();
  389.                     token = nil;
  390.                     }
  391.                 Catch(err)
  392.                     {
  393.                     if(token != nil)
  394.                         token->DisposeDesignator();
  395.                     if(resultToken != nil)
  396.                         resultToken->DisposeDesignator();
  397.                     
  398.                     //
  399.                     // ••• should we really fail again?  maybe we
  400.                     // should not return an error if there is at
  401.                     // least one item in the proxy that returns
  402.                     // a valid property.  For now, we only allow
  403.                     // 'no such object' to pass through.
  404.                     //
  405.                     if(err != errAENoSuchObject)
  406.                         Throw(err);
  407.                     }
  408.                 }
  409.             }
  410.         }
  411.     
  412.     //
  413.     // Since we allow 'no such object' to pass through above,
  414.     // we must fail here if nothing at all was found.
  415.     //
  416.     if(resultToken == nil)
  417.         FailErr(errAENoSuchObject);
  418.     
  419.     return resultToken;
  420.     } // TProxyToken::AccessByProperty 
  421.     
  422. //----------------------------------------------------------------------------------------
  423. // TProxyToken::BuildObjectSpecifier: 
  424. //----------------------------------------------------------------------------------------
  425. TDescriptor TProxyToken::BuildObjectSpecifier(const TAETransaction& t)
  426.     {
  427.     TDescriptor result;
  428.     OSErr err = noErr;
  429.  
  430.     TAbstractScriptableObject* token = nil;
  431.     TDescriptor specifierOfOneObject;
  432.     
  433.     NOREGISTER(token);
  434.     
  435.     //
  436.     // If we need to build an object specifier for a proxy,
  437.     // we instead build a specifier for every element that
  438.     // the proxy represents.
  439.     //
  440.     TAbstractObjectIterator* iter = this->DirectObjectIterator(t);
  441.     for(iter->Reset(t); iter->More(t); iter->Next(t))
  442.         {
  443.         Try
  444.             {
  445.             token = iter->Current(t);
  446.             
  447.             specifierOfOneObject = token->BuildObjectSpecifier(t);
  448.             result.AddItemToList(specifierOfOneObject);
  449.             specifierOfOneObject.Dispose();
  450.             
  451.             token->DisposeDesignator();
  452.             }
  453.         Catch(err)
  454.             {
  455.             specifierOfOneObject.Dispose();
  456.             if(token != nil)
  457.                 token->DisposeDesignator();
  458.             
  459.             result.Dispose();
  460.             Throw(err);
  461.             }
  462.         }
  463.     
  464.     return result;
  465.     } // TProxyToken::BuildObjectSpecifier 
  466.  
  467. //----------------------------------------------------------------------------------------
  468. // TProxyToken::CanReturnDataOfType: 
  469. //----------------------------------------------------------------------------------------
  470. Boolean TProxyToken::CanReturnDataOfType(const TAETransaction& t, DescType propertyName, DescType desiredType)
  471.     {
  472.     TAbstractScriptableObject* token = nil;
  473.     Boolean canDoIt = true;
  474.     Boolean canDoOne = false;
  475.     OSErr err = noErr;
  476.     
  477.     NOREGISTER(token);
  478.     
  479.     if(this->PropertyAppliesToProxy(propertyName) == false)
  480.         {
  481.         //
  482.         // The proxy object can return data of a given type if
  483.         // and only if all of the objects it represents can
  484.         // also return that type.
  485.         //
  486.         TAbstractObjectIterator* iter = this->DirectObjectIterator(t);
  487.         for(iter->Reset(t); iter->More(t); iter->Next(t))
  488.             {
  489.             Try
  490.                 {
  491.                 token = iter->Current(t);
  492.                 canDoIt = token->CanReturnDataOfType(t, propertyName, desiredType);
  493.                 token->DisposeDesignator();
  494.                 token = nil;
  495.                 canDoOne = true;
  496.                 }
  497.             Catch(err)
  498.                 {
  499.                 canDoIt = false;
  500.                 if(token != nil)
  501.                     token->DisposeDesignator();
  502.                 }
  503.             
  504.             if(!canDoIt)
  505.                 break;
  506.             }
  507.         }
  508.     
  509.     //
  510.     // If you can't do at least one, then you can't do it
  511.     //
  512.     if(canDoOne == false)
  513.         canDoIt = false;
  514.     
  515.     //
  516.     // If the proxy objects can't return the specified type,
  517.     // it is still possible to make object specifiers & c.
  518.     //
  519.     if(canDoIt == false)
  520.         canDoIt = Inherited::CanReturnDataOfType(t, propertyName, desiredType);
  521.     
  522.     return canDoIt;
  523.     } // TProxyToken::CanReturnDataOfType 
  524.  
  525. //----------------------------------------------------------------------------------------
  526. // TProxyToken::LookupPropertyDesciption
  527. //----------------------------------------------------------------------------------------
  528. TPropertyDescription TProxyToken::LookupPropertyDesciption(const TAETransaction& t, DescType propertyIdentifier)
  529.     {
  530.     TAbstractScriptableObject* token = nil;
  531.     TPropertyDescription propertyDescription;
  532.     OSErr err = noErr;
  533.     
  534.     propertyDescription.fPropertyIdentifier = 0;
  535.     
  536.     NOREGISTER(token);
  537.     
  538.     //
  539.     // The proxy object can return data of a given type if
  540.     // and only if all of the objects it represents can
  541.     // also return that type.
  542.     //
  543.     TAbstractObjectIterator* iter = this->DirectObjectIterator(t);
  544.     for(iter->Reset(t); iter->More(t); iter->Next(t))
  545.         {
  546.         Try
  547.             {
  548.             token = iter->Current(t);
  549.             const TPropertyDescription* oneDescription = token->DescriptionOfProperty(t, propertyIdentifier);
  550.             token->DisposeDesignator();
  551.             token = nil;
  552.             if(oneDescription != nil)
  553.                 {
  554.                 if(propertyDescription.PropertyIdentifier() != propertyIdentifier)
  555.                     propertyDescription = *oneDescription;
  556.                 else if(propertyDescription != *oneDescription)
  557.                     FailErr(errAEEventFailed); // ◊Error:  Need an error for 'incompatible properties            
  558.                 }
  559.                 // ◊Error:  What should we do if the property is unknown?
  560.                 // If it is unknown in all, we should return.  If it is unknown
  561.                 // in some, we should probably fail with the same error as above
  562.             }
  563.         Catch(err)
  564.             {
  565.             if(token != nil)
  566.                 token->DisposeDesignator();
  567.             Throw(err);
  568.             }
  569.         }
  570.     
  571.     return propertyDescription;
  572.     }
  573.  
  574. //----------------------------------------------------------------------------------------
  575. // TProxyToken::GetProperty: 
  576. //----------------------------------------------------------------------------------------
  577. TDescriptor TProxyToken::GetProperty(const TAETransaction& t, DescType propertyName, DescType desiredType, unsigned long additionalInfo /*= 0*/)
  578.     {
  579.     TAbstractScriptableObject* token = nil;
  580.     TDescriptor resultList;
  581.     TDescriptor intermediate;
  582.     OSErr err = noErr;
  583.     
  584.     NOREGISTER(token);
  585.     
  586.     if(this->PropertyAppliesToProxy(propertyName))
  587.         resultList = Inherited::GetProperty(t, propertyName, desiredType, additionalInfo);
  588.     else
  589.         {    
  590.         //
  591.         // Get data from all of the objects represented by proxy
  592.         //
  593.         TAbstractObjectIterator* iter = this->DirectObjectIterator(t);
  594.         for(iter->Reset(t); iter->More(t); iter->Next(t))
  595.             {
  596.             Try
  597.                 {
  598.                 token = iter->Current(t);
  599.                 intermediate = token->GetDataOfType(t, propertyName, desiredType, additionalInfo);
  600.                 resultList.AppendListAndDispose(intermediate);
  601.                 intermediate.ClearDescriptor();
  602.                 token->DisposeDesignator();
  603.                 token = nil;
  604.                 }
  605.             Catch(err)
  606.                 {
  607.                 intermediate.Dispose();
  608.                 if(token != nil)
  609.                     token->DisposeDesignator();
  610.                 
  611.                 resultList.Dispose();
  612.                 Throw(err);
  613.                 }
  614.             }
  615.         }
  616.             
  617.     return resultList;
  618.     } // TProxyToken::GetProperty 
  619.  
  620. //----------------------------------------------------------------------------------------
  621. // TProxyToken::SetProperty: 
  622. //----------------------------------------------------------------------------------------
  623. void TProxyToken::SetProperty(const TAETransaction& t, DescType propertyName, TDescriptor& data, unsigned long additionalInfo /*= 0*/)
  624.     {
  625.     TAbstractScriptableObject* token = nil;
  626.     long err = noErr;
  627.     
  628.     NOREGISTER(token);
  629.     
  630.     if(this->PropertyAppliesToProxy(propertyName))
  631.         Inherited::SetProperty(t, propertyName, data, additionalInfo);
  632.     else
  633.         {
  634.         //
  635.         // Pass the set data command on to each object represented by proxy
  636.         // Since the order that we try to set these objects in is arbitrary,
  637.         // try to set all of them, but report an error if any one fails.
  638.         //
  639.         TAbstractObjectIterator* iter = this->DirectObjectIterator(t);
  640.         for(iter->Reset(t); iter->More(t); iter->Next(t))
  641.             {
  642.             Try
  643.                 {
  644.                 token = iter->Current(t);
  645.                 token->SetProperty(t, propertyName, data, additionalInfo);
  646.                 token->DisposeDesignator();
  647.                 token = nil;
  648.                 }
  649.             Catch(err)
  650.                 {
  651.                 if(token != nil)
  652.                     token->DisposeDesignator();
  653.                 }
  654.             }
  655.         }
  656.         
  657.     FailErr(err);
  658.     } // TProxyToken::SetProperty 
  659.  
  660. //----------------------------------------------------------------------------------------
  661. // TProxyToken::AECommandDispatch:
  662. //----------------------------------------------------------------------------------------
  663. TDescriptor TProxyToken::AECommandDispatch(const TAETransaction& t, long aeCommandID, long auxInfo /* = 0 */)
  664.     {
  665.     AListOf<TAbstractScriptableObject*>* itemList = this->ConvertThisToList(t, aeCommandID);
  666.     TDescriptor result;
  667.     
  668.     //
  669.     // In the outer loop, do one dispatch involving as
  670.     // many items as possible (all that want the same
  671.     // command dispatcher and the same dispatch selector).
  672.     // The outer loop exits once every item in the list
  673.     // has been added to a collection and dispatched.
  674.     //
  675.     while(itemList->Empty() == false)
  676.         {
  677.         long dispatchSelector = 0;
  678.         TAbstractScriptableObject* dispatcher = nil;
  679.         TAbstractScriptableObject* collection = nil;
  680.         
  681.         //
  682.         // Loop through the items in 'itemList', take all of the
  683.         // items that want the same dispatcher and dispatch selector
  684.         // as the first item and put them into the collection
  685.         //
  686.         for(AnIteratorOfAListOf<TAbstractScriptableObject*> iter(itemList); iter.More(); iter.Next())
  687.             {
  688.             long oneDispatchSelector = 0;
  689.             TAbstractScriptableObject* oneDispatcher = iter.Current()->GetAECommandDispatcher(t, aeCommandID, auxInfo, oneDispatchSelector);
  690.             
  691.             //
  692.             // If we don't have a collection yet, record the
  693.             // dispatcher and selector we'll be collecting
  694.             // for on this iteration of the loop
  695.             //
  696.             if(collection == nil)
  697.                 {
  698.                 dispatcher = oneDispatcher;
  699.                 dispatchSelector = oneDispatchSelector;
  700.                 }
  701.             
  702.             //
  703.             // If we have a match, add this item to the
  704.             // collection and remove it from this loop so
  705.             // that it will not be considered again.
  706.             //
  707.             // n.b. If the item is a designator, then it
  708.             // was cloned when the list was created and
  709.             // will be disposed when the collection is
  710.             // deleted.
  711.             //
  712.             if((dispatcher == oneDispatcher) && (dispatchSelector == oneDispatchSelector))
  713.                 {
  714.                 iter.Current()->AddThisToMarkToken(collection, kSingleItemOrUnion);
  715.                 iter.RemoveCurrent();
  716.                 }
  717.             }
  718.         
  719.         //
  720.         // At this point we should ALWAYS have a collection.
  721.         //
  722.         if(collection != nil)
  723.             {
  724.             TDescriptor intermediate;
  725.             
  726.             //
  727.             // If the dispatcher is nil, then send the command directly
  728.             // to the items in the collection.  This will happen one item
  729.             // at a time; in fact, it's a bit of a waste to make a collection
  730.             // just to do this.  A better optimization would be to have
  731.             // a special loop just for items with a nil dispatcher, and
  732.             // send them off directly.
  733.             //
  734.             // In practice, though, no one should ever call AECommandDispatch
  735.             // unless there's a chance that the command will get dispatched
  736.             // to some other object, so this case (dispatcher == nil) should
  737.             // be rare.
  738.             //
  739.             if(dispatcher == nil)
  740.                 intermediate = collection->AECommand(t, aeCommandID, nil, auxInfo);
  741.             else
  742.                 {
  743.                 intermediate = dispatcher->AECommand(t, aeCommandID, collection, auxInfo);
  744.                 dispatcher->DisposeDesignator();
  745.                 }
  746.             collection->DisposeDesignator();
  747.             collection = nil;
  748.             
  749.             result.AppendListAndDispose(intermediate);
  750.             }
  751.         }
  752.     
  753.     delete itemList;
  754.     
  755.     return result;
  756.     } // TProxyToken::AECommandDispatch
  757.  
  758. //----------------------------------------------------------------------------------------
  759. // TProxyToken::AECommand: 
  760. //----------------------------------------------------------------------------------------
  761. TDescriptor TProxyToken::AECommand(const TAETransaction& t, long aeCommandID, TAbstractScriptableObject* auxObjects /* = nil */, long auxInfo /* = 0 */)
  762.     {
  763.     TAbstractScriptableObject* token = nil;
  764.     TDescriptor resultList;
  765.     TDescriptor resultDesc;
  766.     Boolean atLeastOneWorked = false;
  767.     long err = noErr;
  768.     
  769.     NOREGISTER(token);
  770.     
  771.     //
  772.     // Important:  The index of each window will change as
  773.     // they are closed, so we must reverse the order of iteration
  774.     // if the command is kAEClose.  The same is true of delete.
  775.     //
  776.     // I suppose we could do every command backwards, but
  777.     // that seems a little bit strange
  778.     //
  779.     // Note:  'Select' also has to go backwards, because
  780.     // selecting an item may bring it to the end of the list
  781.     // (this is true in the Finder, at least).
  782.     //
  783.     Boolean direction = kForwardIteration;
  784.     if((aeCommandID == kAEClose) || (aeCommandID == kAESelect) || (aeCommandID == kAEDelete))
  785.         direction = kBackwardIteration;
  786.     
  787.     //
  788.     // Pass the command on to each object represented by proxy
  789.     //
  790.     TAbstractObjectIterator* iter = this->DirectObjectIterator(t);
  791.     for(iter->Reset(t, direction); iter->More(t); iter->Next(t))
  792.         {
  793.         Try
  794.             {
  795.             token = iter->Current(t);
  796.             resultDesc = token->AECommand(t, aeCommandID, auxObjects, auxInfo);
  797.             resultList.AppendListAndDispose(resultDesc);
  798.             resultDesc.ClearDescriptor();
  799.             token->DisposeDesignator();
  800.             token = nil;
  801.             atLeastOneWorked = true;
  802.             }
  803.         Catch(err)
  804.             {
  805.             resultDesc.Dispose();
  806.             if(token != nil)
  807.                 token->DisposeDesignator();
  808.             }
  809.         }
  810.     
  811.     //
  812.     // If at least one item in the set knew how to do the
  813.     // command, then ignore those that didn't know how
  814.     // to do the command (should we be even more generous
  815.     // about hiding errors if at least one item worked?)
  816.     //
  817.     if(atLeastOneWorked && (err == errAEEventNotHandled))
  818.         err = noErr;
  819.     
  820.     //
  821.     // If there was an error, dispose the result and pass the error along
  822.     //
  823.     if(err != noErr)
  824.         {
  825.         resultList.Dispose();
  826.         FailErr(err);
  827.         }
  828.     
  829.     return resultList;
  830.     } // TProxyToken::AECommand 
  831.  
  832. //----------------------------------------------------------------------------------------
  833. // TProxyToken::CreateNewElement: 
  834. //----------------------------------------------------------------------------------------
  835. TAbstractScriptableObject* TProxyToken::CreateNewElement(const TAETransaction& t, DescType newObjectClass, TDescriptor initialData, TDescriptor initialProperties, Boolean& usedInitialData, Boolean& usedInitialProperties)
  836.     {
  837.     TAbstractScriptableObject* token = nil;
  838.     TAbstractScriptableObject* resultToken = nil;
  839.     TAbstractScriptableObject* createdToken = nil;
  840.     long err = noErr;
  841.     
  842.     NOREGISTER(token);
  843.     NOREGISTER(resultToken);
  844.     NOREGISTER(createdToken);
  845.     
  846.     //
  847.     // Pass the create command on to each object represented by proxy
  848.     //
  849.     TAbstractObjectIterator* iter = this->DirectObjectIterator(t);
  850.     for(iter->Reset(t); iter->More(t); iter->Next(t))
  851.         {
  852.         Try
  853.             {
  854.             token = iter->Current(t);
  855.  
  856.             //
  857.             // ◊Script:  what happens if different calls to 'create' return different
  858.             // values for 'unsedInitialData' and 'usedInitialProperties'?  This would be
  859.             // very bad, but it should never happen, because the return value of these
  860.             // booleans should depend on the new object's class and nothing else.
  861.             //
  862.             createdToken = token->CreateNewElement(t, newObjectClass, initialData, initialProperties, usedInitialData, usedInitialProperties);
  863.             createdToken->AddThisToMarkToken(resultToken, kSingleItemOrUnion);
  864.  
  865.             createdToken = nil;
  866.             token->DisposeDesignator();
  867.             token = nil;
  868.             }
  869.         Catch(err)
  870.             {
  871.             if(createdToken != nil)
  872.                 createdToken->DisposeDesignator();
  873.             createdToken = nil;
  874.             if(token != nil)
  875.                 token->DisposeDesignator();
  876.             token = nil;
  877.             }
  878.         }
  879.     
  880.     //
  881.     // If there was an error, dispose the result and pass the error along
  882.     //
  883.     if(err != noErr)
  884.         {
  885.         if(resultToken != nil)
  886.             resultToken->DisposeDesignator();
  887.         FailErr(err);
  888.         }
  889.  
  890.     return resultToken;
  891.     } // TProxyToken::CreateNewElement 
  892.  
  893.  
  894. #pragma segment CFrontCruft
  895.